//===--- Exprs.swift ------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2022-2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import ASTBridging
import SwiftDiagnostics
@_spi(Compiler) import SwiftParser
@_spi(ExperimentalLanguageFeatures) @_spi(RawSyntax) import SwiftSyntax

extension ASTGenVisitor {
  func generate(expr node: ExprSyntax) -> BridgedExpr {
    switch node.as(ExprSyntaxEnum.self) {
    case .arrayExpr(let node):
      return self.generate(arrayExpr: node).asExpr
    case .arrowExpr:
      preconditionFailure("should be handled in generate(sequenceExpr:)")
    case .asExpr:
      preconditionFailure("AsExprSyntax expression only appear after operator folding")
    case .assignmentExpr:
      preconditionFailure("should be handled in generate(sequenceExpr:)")
    case .awaitExpr(let node):
      return self.generate(awaitExpr: node).asExpr
    case .binaryOperatorExpr:
      preconditionFailure("should be handled in generate(sequenceExpr:)")
    case .booleanLiteralExpr(let node):
      return self.generate(booleanLiteralExpr: node).asExpr
    case .borrowExpr(let node):
      return self.generate(borrowExpr: node).asExpr
    case .closureExpr(let node):
      return self.generate(closureExpr: node).asExpr
    case .consumeExpr(let node):
      return self.generate(consumeExpr: node).asExpr
    case .copyExpr(let node):
      return self.generate(copyExpr: node).asExpr
    case .declReferenceExpr(let node):
      return self.generate(declReferenceExpr: node)
    case .dictionaryExpr(let node):
      return self.generate(dictionaryExpr: node).asExpr
    case .discardAssignmentExpr(let node):
      return self.generate(discardAssignmentExpr: node).asExpr
    case .doExpr(let node):
      return self.generate(doExpr: node).asExpr
    case .editorPlaceholderExpr:
      preconditionFailure("EditorPlaceholderExpr is no longer generated by the parser")
    case .floatLiteralExpr(let node):
      return self.generate(floatLiteralExpr: node).asExpr
    case .forceUnwrapExpr(let node):
      return self.generate(forceUnwrapExpr: node).asExpr
    case .functionCallExpr(let node):
      return self.generate(functionCallExpr: node).asExpr
    case .genericSpecializationExpr(let node):
      return self.generate(genericSpecializationExpr: node).asExpr
    case .ifExpr(let node):
      return self.generate(ifExpr: node).asExpr
    case .inOutExpr(let node):
      return self.generate(inOutExpr: node).asExpr
    case .infixOperatorExpr:
      preconditionFailure("InfixOperatorExprSyntax only appear after operator folding")
    case .integerLiteralExpr(let node):
      return self.generate(integerLiteralExpr: node).asExpr
    case .isExpr:
      preconditionFailure("IsExprSyntax only appear after operator folding")
    case .keyPathExpr(let node):
      return self.generate(keyPathExpr: node)
    case .macroExpansionExpr(let node):
      return self.generate(macroExpansionExpr: node).asExpr
    case .memberAccessExpr(let node):
      return self.generate(memberAccessExpr: node)
    case .missingExpr:
      fatalError("unimplemented")
    case .nilLiteralExpr(let node):
      return self.generate(nilLiteralExpr: node).asExpr
    case .optionalChainingExpr(let node):
      return self.generate(optionalChainingExpr: node).asExpr
    case .packElementExpr(let node):
      return self.generate(packElementExpr: node).asExpr
    case .packExpansionExpr(let node):
      return self.generate(packExpansionExpr: node).asExpr
    case .patternExpr(let node):
      return self.generate(patternExpr: node).asExpr
    case .postfixIfConfigExpr(let node):
      return self.generate(postfixIfConfigExpr: node)
    case .postfixOperatorExpr(let node):
      return self.generate(postfixOperatorExpr: node).asExpr
    case .prefixOperatorExpr(let node):
      return self.generate(prefixOperatorExpr: node).asExpr
    case .regexLiteralExpr(let node):
      return self.generate(regexLiteralExpr: node).asExpr
    case .sequenceExpr(let node):
      return self.generate(sequenceExpr: node)
    case .simpleStringLiteralExpr:
      preconditionFailure("SimpleStringLiteral expression only appear in attributes")
    case .stringLiteralExpr(let node):
      return self.generate(stringLiteralExpr: node)
    case .subscriptCallExpr(let node):
      return self.generate(subscriptCallExpr: node).asExpr
    case .superExpr(let node):
      return self.generate(superExpr: node).asExpr
    case .switchExpr(let node):
      return self.generate(switchExpr: node).asExpr
    case .ternaryExpr:
      preconditionFailure("TernaryExprSyntax only appear after operator folding")
    case .tryExpr(let node):
      return self.generate(tryExpr: node)
    case .tupleExpr(let node):
      return self.generate(tupleExpr: node)
    case .typeExpr(let node):
      return self.generate(typeExpr: node).asExpr
    case .unresolvedAsExpr:
      preconditionFailure("should be handled in generate(sequenceExpr:)")
    case .unresolvedIsExpr:
      preconditionFailure("should be handled in generate(sequenceExpr:)")
    case .unresolvedTernaryExpr:
      preconditionFailure("should be handled in generate(sequenceExpr:)")
    case ._canImportExpr, ._canImportVersionInfo:
      preconditionFailure("should not be generated by the parser anymore")
    }
  }

  func generate(expr node: ExprSyntax, postfixIfConfigBaseExpr: BridgedExpr? = nil) -> BridgedExpr {
    if let postfixIfConfigBaseExpr {
      // Generating tail part of a postfix #if expression.
      return self.generatePostfixIfConfigExprSuffix(expr: node, baseExpr: postfixIfConfigBaseExpr)
    } else {
      return self.generate(expr: node)
    }
  }

  /// Generate function for interior of postfix #if expressions. The base expression is provided by the caller.
  ///
  /// ```
  /// foo // <- baseExpr
  /// #if FLAG
  ///   .bar(arg)?[idx]!++ // <- node
  /// #endif
  /// ```
  func generatePostfixIfConfigExprSuffix(expr node: ExprSyntax, baseExpr: BridgedExpr) -> BridgedExpr {
    switch node.as(ExprSyntaxEnum.self) {
    case .memberAccessExpr(let node):
      return self.generate(memberAccessExpr: node, postfixIfConfigBaseExpr: baseExpr)
    case .postfixIfConfigExpr(let node):
      return self.generate(postfixIfConfigExpr: node, postfixIfConfigBaseExpr: baseExpr)
    case .functionCallExpr(let node):
      return self.generate(functionCallExpr: node, postfixIfConfigBaseExpr: baseExpr).asExpr
    case .subscriptCallExpr(let node):
      return self.generate(subscriptCallExpr: node, postfixIfConfigBaseExpr: baseExpr).asExpr
    case .postfixOperatorExpr(let node):
      return self.generate(postfixOperatorExpr: node, postfixIfConfigBaseExpr: baseExpr).asExpr
    case .optionalChainingExpr(let node):
      return self.generate(optionalChainingExpr: node, postfixIfConfigBaseExpr: baseExpr).asExpr
    case .forceUnwrapExpr(let node):
      return self.generate(forceUnwrapExpr: node, postfixIfConfigBaseExpr: baseExpr).asExpr
    default:
      // FIXME: Diagnose 'invalid expression for a postfix #if expression'
      preconditionFailure("expected postfix expression suffix in #if expression clause")
    }
  }

  func generate(arrowExpr node: ArrowExprSyntax) -> BridgedArrowExpr {
    let asyncLoc: BridgedSourceLoc
    let throwsLoc: BridgedSourceLoc
    let thrownTypeExpr: BridgedNullableExpr

    if let effectSpecifiers = node.effectSpecifiers {
      asyncLoc = self.generateSourceLoc(effectSpecifiers.asyncSpecifier)
      throwsLoc = self.generateSourceLoc(effectSpecifiers.throwsClause?.throwsSpecifier)
      if let thrownTypeNode = effectSpecifiers.thrownError {
        let typeExpr = BridgedTypeExpr.createParsed(
          self.ctx,
          type: self.generate(type: thrownTypeNode)
        )
        thrownTypeExpr = BridgedNullableExpr(raw: typeExpr.raw)
      } else {
        thrownTypeExpr = nil
      }
    } else {
      asyncLoc = nil
      throwsLoc = nil
      thrownTypeExpr = nil
    }

    return .createParsed(
      self.ctx,
      asyncLoc: asyncLoc,
      throwsLoc: throwsLoc,
      thrownType: thrownTypeExpr,
      arrowLoc: self.generateSourceLoc(node.arrow)
    )
  }

  func generate(assignmentExpr node: AssignmentExprSyntax) -> BridgedAssignExpr {
    return .createParsed(self.ctx, equalsLoc: self.generateSourceLoc(node.equal))
  }

  func generate(awaitExpr node: AwaitExprSyntax) -> BridgedAwaitExpr {
    return .createParsed(
      self.ctx,
      awaitLoc: self.generateSourceLoc(node.awaitKeyword),
      subExpr: self.generate(expr: node.expression)
    )
  }

  func generate(borrowExpr node: BorrowExprSyntax) -> BridgedBorrowExpr {
    return .createParsed(
      self.ctx,
      borrowLoc: self.generateSourceLoc(node.borrowKeyword),
      subExpr: self.generate(expr: node.expression)
    )
  }

  func generate(binaryOperatorExpr node: BinaryOperatorExprSyntax) -> BridgedUnresolvedDeclRefExpr {
    return createOperatorRefExpr(token: node.operator, kind: .binaryOperator)
  }

  func generate(closureSignature node: ClosureSignatureSyntax) -> GeneratedClosureSignature {
    var result = GeneratedClosureSignature()

    // Attributes.
    self.generateDeclAttributes(attributeList: node.attributes) { attr in
      result.attributes.add(attr)
    }

    if let node = node.capture {
      result.bracketRange = self.generateSourceRange(node)
      let captures = node.items.lazy.map { node in
        self.generate(closureCapture: node)
      }
      result.captureList = captures.bridgedArray(in: self)
    }

    switch node.parameterClause {
    case .parameterClause(let node):
      result.params = self.generate(closureParameterClause: node)
    case .simpleInput(let node):
      result.params = self.generate(closureShorthandParameterList: node)
    case nil:
      result.params = .createParsed(
        self.ctx,
        leftParenLoc: nil,
        parameters: BridgedArrayRef(),
        rightParenLoc: nil
      )
    }

    if let effects = node.effectSpecifiers {
      result.asyncLoc = self.generateSourceLoc(effects.asyncSpecifier)
      result.throwsLoc = self.generateSourceLoc(effects.throwsClause)
      result.thrownType = effects.throwsClause?.type.map(generate(type:))
    }

    if let returnClause = node.returnClause {
      result.arrowLoc = self.generateSourceLoc(returnClause.arrow)
      result.explicitResultType = self.generate(type: returnClause.type)
    }

    result.inLoc = self.generateSourceLoc(node.inKeyword)

    return result
  }

  func generate(closureCapture node: ClosureCaptureSyntax) {
    fatalError("unimplemented")
  }

  struct GeneratedClosureSignature {
    var attributes: BridgedDeclAttributes = BridgedDeclAttributes()
    var bracketRange: BridgedSourceRange = BridgedSourceRange(start: nil, end: nil)
    var captureList: BridgedArrayRef = BridgedArrayRef()
    var capturedSelfDecl: BridgedVarDecl? = nil
    var params: BridgedParameterList? = nil
    var asyncLoc: BridgedSourceLoc = nil
    var throwsLoc: BridgedSourceLoc = nil
    var thrownType: BridgedTypeRepr? = nil
    var arrowLoc: BridgedSourceLoc = nil
    var explicitResultType: BridgedTypeRepr? = nil
    var inLoc: BridgedSourceLoc = nil
  }

  func generate(closureExpr node: ClosureExprSyntax) -> BridgedClosureExpr {
    let signature: GeneratedClosureSignature
    if let node = node.signature {
      signature = self.generate(closureSignature: node)
    } else {
      signature = GeneratedClosureSignature()
    }

    let expr = BridgedClosureExpr.createParsed(
      self.ctx,
      declContext: self.declContext,
      attributes: signature.attributes,
      bracketRange: signature.bracketRange,
      capturedSelfDecl: BridgedNullableVarDecl(raw: signature.capturedSelfDecl?.raw),
      parameterList: signature.params.asNullable,
      asyncLoc: signature.asyncLoc,
      throwsLoc: signature.throwsLoc,
      thrownType: signature.thrownType.asNullable,
      arrowLoc: signature.arrowLoc,
      explicitResultType: signature.explicitResultType.asNullable,
      inLoc: signature.inLoc
    )

    let body = self.withDeclContext(expr.asDeclContext) {
      BridgedBraceStmt.createParsed(
        self.ctx,
        lBraceLoc: self.generateSourceLoc(node.leftBrace),
        elements: self.generate(codeBlockItemList: node.statements),
        rBraceLoc: self.generateSourceLoc(node.rightBrace)
      )
    }

    if signature.params == nil {
      // TODO: Handle doller identifiers inside the closure.
      let loc = self.generateSourceLoc(node.leftBrace)
      let params = BridgedParameterList.createParsed(
        self.ctx,
        leftParenLoc: loc,
        parameters: .init(),
        rightParenLoc: loc
      )
      expr.setParameterList(params)
      expr.setHasAnonymousClosureVars()
    }

    expr.setBody(body)

    if signature.captureList.count > 0 {
      // TODO: CaptureListExpr.
    }

    return expr
  }

  func generate(consumeExpr node: ConsumeExprSyntax) -> BridgedConsumeExpr {
    return .createParsed(
      self.ctx,
      consumeLoc: self.generateSourceLoc(node.consumeKeyword),
      subExpr: self.generate(expr: node.expression)
    )
  }

  func generate(copyExpr node: CopyExprSyntax) -> BridgedCopyExpr {
    return .createParsed(
      self.ctx,
      copyLoc: self.generateSourceLoc(node.copyKeyword),
      subExpr: self.generate(expr: node.expression)
    )
  }

  func generate(forceUnwrapExpr node: ForceUnwrapExprSyntax, postfixIfConfigBaseExpr: BridgedExpr? = nil) -> BridgedForceValueExpr {
    return .createParsed(
      self.ctx,
      subExpr: self.generate(expr: node.expression, postfixIfConfigBaseExpr: postfixIfConfigBaseExpr),
      exclaimLoc: self.generateSourceLoc(node.exclamationMark)
    )
  }

  func generateArgumentList(
    leftParen: TokenSyntax?,
    labeledExprList: LabeledExprListSyntax,
    rightParen: TokenSyntax?,
    trailingClosure: ClosureExprSyntax?,
    additionalTrailingClosures: MultipleTrailingClosureElementListSyntax?
  ) -> BridgedArgumentList {

    let bridgedArgs: BridgedArrayRef = {
      // Arguments before ')'
      let normalArgs = labeledExprList.lazy.map({ elem in
        let labelInfo = elem.label.map(self.generateIdentifierAndSourceLoc(_:))
        return BridgedCallArgument(
          labelLoc: labelInfo?.sourceLoc ?? BridgedSourceLoc(),
          label: labelInfo?.identifier ?? BridgedIdentifier(),
          argExpr: self.generate(expr: elem.expression)
        )
      })
      guard let trailingClosure else {
        // FIXME: Diagnose, instead of precondition.
        precondition(
          additionalTrailingClosures == nil || additionalTrailingClosures!.isEmpty,
          "multiple trailing closures without the first trailing closure"
        )
        return normalArgs.bridgedArray(in: self)
      }

      // The first trailing closure.
      let bridgedTrailingClosureArg = BridgedCallArgument(
        labelLoc: nil,
        label: nil,
        argExpr: self.generate(closureExpr: trailingClosure).asExpr
      )
      let normalArgsAndClosure = ConcatCollection(normalArgs, CollectionOfOne(bridgedTrailingClosureArg))
      guard let additionalTrailingClosures else {
        return normalArgsAndClosure.bridgedArray(in: self)
      }

      // Remaining trailing closures.
      let additions = additionalTrailingClosures.lazy.map { argNode in
        return BridgedCallArgument(
          labelLoc: self.generateSourceLoc(argNode.label),
          label: self.generateIdentifier(argNode.label),
          argExpr: self.generate(closureExpr: argNode.closure).asExpr
        )
      }
      let allArgs = ConcatCollection(normalArgsAndClosure, additions)
      return allArgs.bridgedArray(in: self)
    }()

    // This should be "nil" value if there's no trailing closure. Passing the number
    // of the normal arguments because we don't have a convenient way to pass
    // Optional to ASTBridging,  ASTBridging can know it's "nil" if
    // bridgedArgs.count == firstTrailingClosureIndex
    let firstTrailingClosureIndex = labeledExprList.count

    return BridgedArgumentList.createParsed(
      self.ctx,
      lParenLoc: self.generateSourceLoc(leftParen),
      args: bridgedArgs,
      rParenLoc: self.generateSourceLoc(rightParen),
      firstTrailingClosureIndex: firstTrailingClosureIndex
    )
  }

  func generate(functionCallExpr node: FunctionCallExprSyntax, postfixIfConfigBaseExpr: BridgedExpr? = nil) -> BridgedCallExpr {
    if !node.arguments.isEmpty || node.trailingClosure == nil {
      if node.leftParen == nil {
        self.diagnose(.missingChildToken(parent: node, kindOfTokenMissing: .leftParen))
      }
      if node.rightParen == nil {
        self.diagnose(.missingChildToken(parent: node, kindOfTokenMissing: .rightParen))
      }
    }

    let callee = self.generate(expr: node.calledExpression, postfixIfConfigBaseExpr: postfixIfConfigBaseExpr)
    let arguments = generateArgumentList(
      leftParen: node.leftParen,
      labeledExprList: node.arguments,
      rightParen: node.rightParen,
      trailingClosure: node.trailingClosure,
      additionalTrailingClosures: node.additionalTrailingClosures
    )

    return .createParsed(self.ctx, fn: callee, args: arguments)
  }

  func generateDeclNameRef(declReferenceExpr node: DeclReferenceExprSyntax) -> (
    name: BridgedDeclNameRef, loc: BridgedDeclNameLoc
  ) {
    let baseName: BridgedDeclBaseName
    switch node.baseName.keywordKind {
    case .`init`:
      baseName = .createConstructor()
    case .deinit:
      baseName = .createDestructor()
    case .subscript:
      baseName = .createSubscript()
    default:
      baseName = .createIdentifier(self.generateIdentifier(node.baseName))
    }
    let baseNameLoc = self.generateSourceLoc(node.baseName)

    if let argumentClause = node.argumentNames {
      if argumentClause.arguments.isEmpty {
        return (
          name: .createParsed(
            self.ctx,
            baseName: baseName,
            argumentLabels: BridgedArrayRef()
          ),
          loc: .createParsed(baseNameLoc)
        )
      } else {
        let labels = argumentClause.arguments.lazy.map {
          self.generateIdentifier($0.name)
        }
        let labelLocs = argumentClause.arguments.lazy.map {
          self.generateSourceLoc($0.name)
        }
        return (
          name: .createParsed(
            self.ctx,
            baseName: baseName,
            argumentLabels: labels.bridgedArray(in: self)
          ),
          loc: .createParsed(
            self.ctx,
            baseNameLoc: baseNameLoc,
            lParenLoc: self.generateSourceLoc(argumentClause.leftParen),
            argumentLabelLocs: labelLocs.bridgedArray(in: self),
            rParenLoc: self.generateSourceLoc(argumentClause.rightParen)
          )
        )
      }
    } else {
      return (
        name: .createParsed(baseName),
        loc: .createParsed(baseNameLoc)
      )
    }
  }

  func generateEditorPlaceholderExpr(token: TokenSyntax) -> BridgedEditorPlaceholderExpr {
    guard let data = token.rawEditorPlaceHolderData else {
      preconditionFailure("EditorPlaceholderExprSyntax.placeholder must be a placeholder token")
    }
    let (identifier, loc) = self.generateIdentifierAndSourceLoc(token)
    let placeholderTyR: BridgedTypeRepr?
    let expansionTyR: BridgedTypeRepr?
    func parseType(text: SyntaxText) -> BridgedTypeRepr {
      var parser = Parser(UnsafeBufferPointer(start: text.baseAddress, count: text.count))
      let syntax = TypeSyntax.parse(from: &parser)
      return self.generate(type: syntax)
    }
    if let typeText = data.typeText {
      placeholderTyR = parseType(text: typeText)
    } else {
      placeholderTyR = nil
    }
    if data.typeText == data.typeForExpansionText {
      expansionTyR = placeholderTyR
    } else {
      // `typeForExpansionText` is guaranteed to be non-nil if `typeText` is non-nil,
      expansionTyR = parseType(text: data.typeForExpansionText!)
    }
    return .createParsed(
      self.ctx,
      placeholder: identifier,
      loc: loc,
      placeholderType: placeholderTyR.asNullable,
      expansionType: expansionTyR.asNullable
    )
  }

  func generate(declReferenceExpr node: DeclReferenceExprSyntax) -> BridgedExpr {
    if node.baseName.isEditorPlaceholder {
      return generateEditorPlaceholderExpr(token: node.baseName).asExpr
    }
    if node.baseName.rawTokenKind == .dollarIdentifier {
      // TODO: Handle dollar identifier in closure decl context.
      // It's done in C++ Parser because it needs to handle inactive #if regions.
    }
    let nameAndLoc = generateDeclNameRef(declReferenceExpr: node)
    return BridgedUnresolvedDeclRefExpr.createParsed(
      self.ctx,
      name: nameAndLoc.name,
      kind: .ordinary,
      loc: nameAndLoc.loc
    ).asExpr
  }

  func generate(discardAssignmentExpr node: DiscardAssignmentExprSyntax) -> BridgedDiscardAssignmentExpr {
    return .createParsed(self.ctx, loc: self.generateSourceLoc(node.wildcard))
  }

  func generate(doExpr node: DoExprSyntax) -> BridgedSingleValueStmtExpr {
    let stmt = self.generate(doStmtOrExpr: node)

    // Wrap in a SingleValueStmtExpr to embed as an expression.
    return .createWithWrappedBranches(
      ctx,
      stmt: stmt,
      declContext: declContext,
      mustBeExpr: true
    )
  }

  func generate(keyPathComponent node: KeyPathComponentSyntax, baseExpr: BridgedExpr) -> BridgedExpr {
    switch node.component {
    case .property(let prop):
      let dotLoc = self.generateSourceLoc(node.period)
      if prop.declName.baseName.presence == .missing {
        return BridgedErrorExpr.create(
          self.ctx,
          loc: BridgedSourceRange(start: dotLoc, end: dotLoc)
        ).asExpr
      } else if prop.declName.baseName.keywordKind == .`self` {
        // TODO: Diagnose if there's arguments
        assert(prop.declName.argumentNames == nil)

        return BridgedDotSelfExpr.createParsed(
          self.ctx,
          subExpr: baseExpr,
          dotLoc: dotLoc,
          selfLoc: self.generateSourceLoc(prop.declName)
        ).asExpr
      } else {
        let declNameRef = self.generateDeclNameRef(declReferenceExpr: prop.declName)
        return BridgedUnresolvedDotExpr.createParsed(
          self.ctx,
          base: baseExpr,
          dotLoc: dotLoc,
          name: declNameRef.name,
          nameLoc: declNameRef.loc
        ).asExpr
      }

    case .optional(let comp):
      if comp.questionOrExclamationMark.rawText == "!" {
        return BridgedForceValueExpr.createParsed(
          self.ctx,
          subExpr: baseExpr,
          exclaimLoc: self.generateSourceLoc(comp.questionOrExclamationMark)
        ).asExpr
      } else {
        return BridgedBindOptionalExpr.createParsed(
          self.ctx,
          subExpr: baseExpr,
          questionLoc: self.generateSourceLoc(comp.questionOrExclamationMark)
        ).asExpr
      }

    case .subscript(let comp):
      return BridgedSubscriptExpr.createParsed(
        self.ctx,
        baseExpr: baseExpr,
        args: self.generateArgumentList(
          leftParen: comp.leftSquare,
          labeledExprList: comp.arguments,
          rightParen: comp.rightSquare,
          trailingClosure: nil,
          additionalTrailingClosures: nil
        )
      ).asExpr
    }
  }

  func generate(keyPathExpr node: KeyPathExprSyntax) -> BridgedExpr {
    guard !node.components.isEmpty else {
      // FIXME: Diagnostics KeyPath expression without any component.
      return BridgedErrorExpr.create(self.ctx, loc: self.generateSourceRange(node)).asExpr
    }

    var rootExpr: BridgedExpr?
    if let parsedType = node.root, !parsedType.is(MissingTypeSyntax.self) {
      let rootType = self.generate(type: parsedType)
      rootExpr = BridgedTypeExpr.createParsed(self.ctx, type: rootType).asExpr
    } else {
      rootExpr = nil
    }

    var inRoot = rootExpr != nil
    var pathExpr: BridgedExpr? = nil

    for component in node.components {
      if inRoot {
        switch component.component {
        case // "root" expression is separated by '.?' or '.[idx]'
          .optional(_) where component.period != nil,
          .subscript(_) where component.period != nil:
          inRoot = false
        default:
          rootExpr = self.generate(keyPathComponent: component, baseExpr: rootExpr!)
          continue
        }
      }

      if pathExpr == nil {
        // 'KeyPathDotExpr' is a dummy base expression.
        pathExpr = BridgedKeyPathDotExpr.createParsed(
          self.ctx,
          // Use 'component' instead of 'component.period' because period can
          // be nil (e.g. '\?'), but 'loc' must be a valid location.
          loc: self.generateSourceLoc(component)
        ).asExpr
      }

      pathExpr = self.generate(keyPathComponent: component, baseExpr: pathExpr!)
    }

    return BridgedKeyPathExpr.createParsed(
      self.ctx,
      backslashLoc: self.generateSourceLoc(node.backslash),
      parsedRoot: rootExpr.asNullable,
      parsedPath: pathExpr.asNullable,
      hasLeadingDot: rootExpr == nil
    ).asExpr
  }

  struct FreestandingMacroExpansionInfo {
    var poundLoc: BridgedSourceLoc
    var macroNameRef: BridgedDeclNameRef
    var macroNameLoc: BridgedDeclNameLoc
    var leftAngleLoc: BridgedSourceLoc
    var genericArgs: BridgedArrayRef
    var rightAngleLoc: BridgedSourceLoc
    var arguments: BridgedNullableArgumentList
  }

  func generate(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> FreestandingMacroExpansionInfo {
    let poundLoc = self.generateSourceLoc(node.pound)
    let nameLoc = self.generateIdentifierAndSourceLoc(node.macroName)

    let leftAngleLoc: BridgedSourceLoc
    let genericArgs: [BridgedTypeRepr]
    let rightAngleLoc: BridgedSourceLoc
    if let generics = node.genericArgumentClause {
      leftAngleLoc = self.generateSourceLoc(generics.leftAngle)
      genericArgs = generics.arguments.map {
        self.generate(genericArgument: $0.argument)
      }
      rightAngleLoc = self.generateSourceLoc(generics.rightAngle)
    } else {
      leftAngleLoc = nil
      genericArgs = []
      rightAngleLoc = nil
    }

    let arguments: BridgedArgumentList?
    if (node.leftParen != nil || node.trailingClosure != nil) {
      arguments = self.generateArgumentList(
        leftParen: node.leftParen,
        labeledExprList: node.arguments,
        rightParen: node.rightParen,
        trailingClosure: node.trailingClosure,
        additionalTrailingClosures: node.additionalTrailingClosures
      )
    } else {
      arguments = nil
    }

    return FreestandingMacroExpansionInfo(
      poundLoc: poundLoc,
      macroNameRef: .createParsed(.createIdentifier(nameLoc.identifier)),
      macroNameLoc: .createParsed(nameLoc.sourceLoc),
      leftAngleLoc: leftAngleLoc,
      genericArgs: genericArgs.lazy.bridgedArray(in: self),
      rightAngleLoc: rightAngleLoc,
      arguments: arguments.asNullable
    )
  }

  func generate(macroExpansionExpr node: MacroExpansionExprSyntax) -> BridgedMacroExpansionExpr {
    let info = self.generate(freestandingMacroExpansion: node)
    return .createParsed(
      self.declContext,
      poundLoc: info.poundLoc,
      macroNameRef: info.macroNameRef,
      macroNameLoc: info.macroNameLoc,
      leftAngleLoc: info.leftAngleLoc,
      genericArgs: info.genericArgs,
      rightAngleLoc: info.rightAngleLoc,
      args: info.arguments
    )
  }

  func generate(memberAccessExpr node: MemberAccessExprSyntax, postfixIfConfigBaseExpr: BridgedExpr? = nil) -> BridgedExpr {
    let baseExpr: BridgedExpr?
    if let base = node.base {
      baseExpr = self.generate(expr: base, postfixIfConfigBaseExpr: postfixIfConfigBaseExpr)
    } else if let postfixIfConfigBaseExpr {
      // Dot member syntax right after '#if' line. E.g.
      //   foo // <- postfixIfConfigBaseExpr
      //   #if FLAG
      //     .bar // <- Generating this.
      //     .baz
      //   #endif
      baseExpr = postfixIfConfigBaseExpr
    } else {
      baseExpr = nil
    }

    let dotLoc = self.generateSourceLoc(node.period)
    let nameAndLoc = generateDeclNameRef(declReferenceExpr: node.declName)

    if let baseExpr {
      if node.declName.baseName.keywordKind == .`self` {
        // TODO: Diagnose if there's arguments
        assert(node.declName.argumentNames == nil)

        return BridgedDotSelfExpr.createParsed(
          self.ctx,
          subExpr: baseExpr,
          dotLoc: dotLoc,
          selfLoc: self.generateSourceLoc(node.declName)
        ).asExpr
      } else {
        return BridgedUnresolvedDotExpr.createParsed(
          self.ctx,
          base: baseExpr,
          dotLoc: dotLoc,
          name: nameAndLoc.name,
          nameLoc: nameAndLoc.loc
        ).asExpr
      }
    } else {
      return BridgedUnresolvedMemberExpr.createParsed(
        self.ctx,
        dotLoc: dotLoc,
        name: nameAndLoc.name,
        nameLoc: nameAndLoc.loc
      ).asExpr
    }
  }

  func generate(genericSpecializationExpr node: GenericSpecializationExprSyntax) -> BridgedUnresolvedSpecializeExpr {
    let base = self.generate(expr: node.expression)
    let generics = node.genericArgumentClause
    let lAngleLoc = self.generateSourceLoc(generics.leftAngle)
    let genericArguments = generics.arguments.lazy.map {
      self.generate(genericArgument: $0.argument)
    }
    let rAngleLoc = self.generateSourceLoc(generics.rightAngle)
    return .createParsed(
      self.ctx,
      subExpr: base,
      lAngleLoc: lAngleLoc,
      arguments: genericArguments.bridgedArray(in: self),
      rAngleLoc: rAngleLoc
    )
  }

  func generate(optionalChainingExpr node: OptionalChainingExprSyntax, postfixIfConfigBaseExpr: BridgedExpr? = nil) -> BridgedBindOptionalExpr {
    return .createParsed(
      self.ctx,
      subExpr: self.generate(expr: node.expression, postfixIfConfigBaseExpr: postfixIfConfigBaseExpr),
      questionLoc: self.generateSourceLoc(node.questionMark)
    )
  }

  func generate(packElementExpr node: PackElementExprSyntax) -> BridgedPackElementExpr {
    return .createParsed(
      self.ctx,
      eachLoc: self.generateSourceLoc(node.eachKeyword),
      packRefExpr: self.generate(expr: node.pack)
    )
  }

  func generate(packExpansionExpr node: PackExpansionExprSyntax) -> BridgedPackExpansionExpr {
    return .createParsed(
      self.ctx,
      repeatLoc: self.generateSourceLoc(node.repeatKeyword),
      patternExpr: self.generate(expr: node.repetitionPattern)
    )
  }

  func generate(patternExpr node: PatternExprSyntax) -> BridgedUnresolvedPatternExpr {
    return .createParsed(
      self.ctx,
      pattern: self.generate(pattern: node.pattern)
    )
  }

  func generate(inOutExpr node: InOutExprSyntax) -> BridgedInOutExpr {
    let subExpr = self.generate(expr: node.expression)
    return .createParsed(
      self.ctx,
      loc: self.generateSourceLoc(node.ampersand),
      subExpr: subExpr
    )
  }

  func generate(ifExpr node: IfExprSyntax) -> BridgedSingleValueStmtExpr {
    let stmt = generateIfStmt(ifExpr: node).asStmt

    // Wrap in a SingleValueStmtExpr to embed as an expression.
    return .createWithWrappedBranches(
      ctx,
      stmt: stmt,
      declContext: declContext,
      mustBeExpr: true
    )
  }

  func generate(postfixIfConfigExpr node: PostfixIfConfigExprSyntax, postfixIfConfigBaseExpr: BridgedExpr? = nil) -> BridgedExpr {
    let baseExpr: BridgedExpr
    if let base = node.base {
      baseExpr = self.generate(expr: base, postfixIfConfigBaseExpr: postfixIfConfigBaseExpr)
    } else if let postfixIfConfigBaseExpr {
      // This is a nested postifx #if expression. E.g.
      //
      //   foo // <- postfixIfConfigBaseExpr
      //   #if FLAG
      //     #if FLAG2 // <- This
      //       .bar
      //     #endif
      //     .baz
      //   #endif
      //
      baseExpr = postfixIfConfigBaseExpr
    } else {
      // FIXME: Diagnostics
      preconditionFailure("expected PostfixIfConfigExprSyntax.base not nil")
    }

    guard let active = self.activeClause(in: node.config) else {
      return baseExpr
    }
    guard case .postfixExpression(let parsedTail) = active.elements else {
      // FIXME: Diagnostics
      preconditionFailure("expected postfixExpression in IfConfigClauseSyntax.Elements")
    }
    return self.generatePostfixIfConfigExprSuffix(expr: parsedTail, baseExpr: baseExpr)
  }

  func generate(postfixOperatorExpr node: PostfixOperatorExprSyntax, postfixIfConfigBaseExpr: BridgedExpr? = nil) -> BridgedPostfixUnaryExpr {
    let operand = self.generate(expr: node.expression, postfixIfConfigBaseExpr: postfixIfConfigBaseExpr)
    return .createParsed(
      self.ctx,
      operator: self.createOperatorRefExpr(
        token: node.operator,
        kind: .postfixOperator
      ).asExpr,
      operand: operand
    )
  }

  func generate(prefixOperatorExpr node: PrefixOperatorExprSyntax) -> BridgedPrefixUnaryExpr {
    return .createParsed(
      self.ctx,
      operator: self.createOperatorRefExpr(
        token: node.operator,
        kind: .prefixOperator
      ).asExpr,
      operand: self.generate(expr: node.expression)
    )
  }

  func generate(regexLiteralExpr node: RegexLiteralExprSyntax) -> BridgedRegexLiteralExpr {
    // Copy the regex string to the ASTContext.
    var str = node.trimmedDescription
    let regexText = str.withBridgedString {
      self.ctx.allocateCopy(string: $0)
    }
    return .createParsed(
      self.ctx,
      loc: self.generateSourceLoc(node),
      regexText: regexText
    )
  }

  func generate(sequenceExpr node: SequenceExprSyntax) -> BridgedExpr {
    assert(
      !node.elements.count.isMultiple(of: 2),
      "SequenceExpr must have odd number of elements"
    )

    guard node.elements.count > 1 else {
      // Should be unreachable if the `node` is a parsed by `SwiftParser`.
      return self.generate(expr: node.elements.first!)
    }

    // NOTE: we can't just generate(expr:) for each elements because
    // SwiftSyntax.SequenceExprSyntax and swift::SequenceExpr has mismatch in the
    // element representations. e.g. 'as' and 'is'.

    // FIXME: Avoid Swift.Array.
    var elements: [BridgedExpr] = []
    elements.reserveCapacity(node.elements.count)

    var iter = node.elements.makeIterator()
    while let node = iter.next() {
      switch node.as(ExprSyntaxEnum.self) {
      case .arrowExpr(let node):
        elements.append(self.generate(arrowExpr: node).asExpr)
      case .assignmentExpr(let node):
        elements.append(self.generate(assignmentExpr: node).asExpr)
      case .binaryOperatorExpr(let node):
        elements.append(self.generate(binaryOperatorExpr: node).asExpr)
      case .unresolvedAsExpr(let node):
        let oper = self.generate(
          unresolvedAsExpr: node,
          typeExpr: iter.next()!.cast(TypeExprSyntax.self)
        )
        elements.append(oper)
        elements.append(oper)
      case .unresolvedIsExpr(let node):
        let oper = self.generate(
          unresolvedIsExpr: node,
          typeExpr: iter.next()!.cast(TypeExprSyntax.self)
        )
        elements.append(oper.asExpr)
        elements.append(oper.asExpr)
      case .unresolvedTernaryExpr(let node):
        elements.append(self.generate(unresolvedTernaryExpr: node).asExpr)
      default:
        // Operand.
        elements.append(self.generate(expr: node))
      }
    }

    return BridgedSequenceExpr.createParsed(
      self.ctx,
      exprs: elements.lazy.bridgedArray(in: self)
    ).asExpr
  }

  func generate(subscriptCallExpr node: SubscriptCallExprSyntax, postfixIfConfigBaseExpr: BridgedExpr? = nil) -> BridgedSubscriptExpr {
    let callee = generate(expr: node.calledExpression, postfixIfConfigBaseExpr: postfixIfConfigBaseExpr)
    let arguments = generateArgumentList(
      leftParen: node.leftSquare,
      labeledExprList: node.arguments,
      rightParen: node.rightSquare,
      trailingClosure: node.trailingClosure,
      additionalTrailingClosures: node.additionalTrailingClosures
    )

    return .createParsed(self.ctx, baseExpr: callee, args: arguments)
  }

  func generate(superExpr node: SuperExprSyntax) -> BridgedSuperRefExpr {
    return .createParsed(self.ctx, superLoc: self.generateSourceLoc(node))
  }

  func generate(switchExpr node: SwitchExprSyntax) -> BridgedSingleValueStmtExpr {
    let stmt = self.generateSwitchStmt(switchExpr: node)

    // Wrap in a SingleValueStmtExpr to embed as an expression.
    return .createWithWrappedBranches(
      ctx,
      stmt: stmt.asStmt,
      declContext: declContext,
      mustBeExpr: true
    )
  }

  func generate(tryExpr node: TryExprSyntax) -> BridgedExpr {
    let tryLoc = self.generateSourceLoc(node.tryKeyword)
    let subExpr = self.generate(expr: node.expression)

    switch node.questionOrExclamationMark {
    case nil:
      return BridgedTryExpr.createParsed(
        self.ctx,
        tryLoc: tryLoc,
        subExpr: subExpr
      ).asExpr
    case let exclaim? where exclaim.rawTokenKind == .exclamationMark:
      return BridgedForceTryExpr.createParsed(
        self.ctx,
        tryLoc: tryLoc,
        subExpr: subExpr,
        exclaimLoc: self.generateSourceLoc(exclaim)
      ).asExpr
    case let question? where question.rawTokenKind == .postfixQuestionMark:
      return BridgedOptionalTryExpr.createParsed(
        self.ctx,
        tryLoc: tryLoc,
        subExpr: subExpr,
        questionLoc: self.generateSourceLoc(question)
      ).asExpr
    default:
      preconditionFailure("TryExprSyntax.questionOrExclamationMark must be .exclamationMark or .postfixQuestionMark")
    }
  }

  func generate(tupleExpr node: TupleExprSyntax) -> BridgedExpr {
    if node.elements.count == 1,
       let first = node.elements.first,
       first.label == nil,
       !first.expression.is(PackExpansionExprSyntax.self) {
      return BridgedParenExpr.createParsed(
        self.ctx,
        leftParenLoc: self.generateSourceLoc(node.leftParen),
        expr: self.generate(expr: node.elements.first!.expression),
        rightParenLoc: self.generateSourceLoc(node.rightParen)
      ).asExpr
    }

    let expressions = node.elements.lazy.map {
      self.generate(expr: $0.expression)
    }
    let labels = node.elements.lazy.map {
      self.generateIdentifier($0.label)
    }
    let labelLocations = node.elements.lazy.map {
      if let label = $0.label {
        return self.generateSourceLoc(label)
      }

      return self.generateSourceLoc($0)
    }

    return BridgedTupleExpr.createParsed(
      self.ctx,
      leftParenLoc: self.generateSourceLoc(node.leftParen),
      exprs: expressions.bridgedArray(in: self),
      labels: labels.bridgedArray(in: self),
      labelLocs: labelLocations.bridgedArray(in: self),
      rightParenLoc: self.generateSourceLoc(node.rightParen)
    ).asExpr
  }

  func generate(typeExpr node: TypeExprSyntax) -> BridgedTypeExpr {
    return .createParsed(
      self.ctx,
      type: self.generate(type: node.type)
    )
  }

  func generate(unresolvedAsExpr node: UnresolvedAsExprSyntax, typeExpr typeNode: TypeExprSyntax) -> BridgedExpr {
    let type = self.generate(type: typeNode.type)
    let asLoc = self.generateSourceLoc(node.asKeyword)

    switch node.questionOrExclamationMark {
    case nil:
      return BridgedCoerceExpr.createParsed(
        self.ctx,
        asLoc: asLoc,
        type: type
      ).asExpr
    case let question? where question.rawTokenKind == .postfixQuestionMark:
      return BridgedConditionalCheckedCastExpr.createParsed(
        self.ctx,
        asLoc: asLoc,
        questionLoc: self.generateSourceLoc(question),
        type: type
      ).asExpr
    case let exclaim? where exclaim.rawTokenKind == .exclamationMark:
      return BridgedForcedCheckedCastExpr.createParsed(
        self.ctx,
        asLoc: asLoc,
        exclaimLoc: self.generateSourceLoc(exclaim),
        type: type
      ).asExpr
    case _?:
      preconditionFailure("UnresolvedAsExprSyntax must have '?' or '!'")
    }
  }

  func generate(unresolvedIsExpr node: UnresolvedIsExprSyntax, typeExpr typeNode: TypeExprSyntax) -> BridgedIsExpr {
    return .createParsed(
      self.ctx,
      isLoc: self.generateSourceLoc(node.isKeyword),
      type: self.generate(type: typeNode.type)
    )
  }

  func generate(unresolvedTernaryExpr node: UnresolvedTernaryExprSyntax) -> BridgedTernaryExpr {
    return .createParsed(
      self.ctx,
      questionLoc: self.generateSourceLoc(node.questionMark),
      thenExpr: self.generate(expr: node.thenExpression),
      colonLoc: self.generateSourceLoc(node.colon)
    )
  }

  // NOTE: When implementing new `generate(expr:)`, please update `isExprMigrated(_:)`.
}

extension ASTGenVisitor {
  fileprivate func createOperatorRefExpr(
    token node: TokenSyntax,
    kind: BridgedDeclRefKind
  ) -> BridgedUnresolvedDeclRefExpr {
    let (name, nameLoc) = self.generateIdentifierAndSourceLoc(node)

    return .createParsed(
      self.ctx,
      name: .createParsed(.createIdentifier(name)),
      kind: kind,
      loc: .createParsed(nameLoc)
    );
  }
}
